'''
Created on 21/10/2012

@author: Chris
'''

from time import sleep
from threading import Thread, Event
from Tkinter import Tk
from ui import init_menu
from env import ConfigManager
from widget import RepositoryBrowser, HistoryBrowser
from gitcmd import commit_all_files

#=======================================================================================
class DMApp(object):
#=======================================================================================
    '''Draft Manager Main class'''
    
#=======================================================================================    
    def __init__(self):
#=======================================================================================
        self.root = Tk()
        self.root.title("Draft Manager")
        
        xoffset = self.root.winfo_screenwidth() * 0.2
        yoffset = self.root.winfo_screenheight() * 0.2
        width  = 830
        height = 450
        self.root.geometry("%dx%d+%d+%d" % (width,height,xoffset, yoffset))
        
        # create menu 
        init_menu(self, self.root)
        
        self.config = ConfigManager()
        self.repo_dirs = self.config.get_repo_config()
        
        # save repository objects for auto-save function
        self.auto_save_repos = self.config.get_auto_saved_repo()
        

        # set ui
        self.repo_broswer = RepositoryBrowser(self.root,self.repo_dirs)
        self.repo_broswer.grid(column=0, row=0, sticky='nw', padx=5, pady=7)
        self.history_broswer = HistoryBrowser(self.repo_broswer, self.root)
        self.history_broswer.grid(column=0, row=1, sticky='nw', padx=5)

        # fix the main window size
        self.root.resizable(width=False, height=False)
        
        
        self.auto_save_interval = self.config.get_auto_save_interval()
   
        # set thread stop event
        self.thread_stop = Event()
        # creat two threads to monitor updating browser and commit
        self.update_thread = SysMonitorThread(self, "update", 1)
        self.commit_thread = SysMonitorThread(self, "commit")
        self.update_thread.start()
        self.commit_thread.start()

        # set deconstruction for root quit
        self.root.protocol("WM_DELETE_WINDOW", self.quit)
        self.root.mainloop()
        
        
#=======================================================================================    
    def add_repo_node(self, repo_name, repo_dir, repo):
#=======================================================================================
        '''
        interface for adding new repository to config file 
        also update the cache of repository in repository browser
        '''
        self.config.add_repo_node(repo_name, repo_dir);
        self.repo_broswer.add_new_repo(repo_name, repo_dir, repo)
        
        # update file browser after addition
        self.repo_broswer.update_files_in_repo()  

#=======================================================================================    
    def remove_repo_node(self):
#=======================================================================================
        '''
        interface for removing repository from config 
        and update the cache of repository in repository broswer
        '''
        repo_name = self.repo_broswer.get_selected_repo_name()
        self.config.remove_repo_node(repo_name)
        # reload config
        self.repo_dirs = self.config.get_repo_config()
        self.repo_broswer.remove_repo(self.repo_dirs)
        
#=======================================================================================    
    def get_config(self):
#=======================================================================================
        '''
        interface for accessing config
        '''
        return self.config
    
#=======================================================================================    
    def get_current_repo_file(self):
#=======================================================================================
        '''
        interface for accessing selected repository and selected file
        '''
        selected_repo = self.repo_broswer.get_selected_repo()
        selected_file_property = self.repo_broswer.get_selected_file()
        
        return selected_repo, selected_file_property

#=======================================================================================
    def create_repo(self, repo_name, repo_dir):
#=======================================================================================
        '''
        create repository object and save it with cache of repository browser 
        '''
        # if the same repository object has existed in cache then return
        is_repo_in = self.repo_broswer.is_repo_in_cache(repo_name)
        
        if not is_repo_in:
            self.repo_broswer.save_repo_in_cache(repo_name, repo_dir)
            
        
        repo = self.repo_broswer.get_repo_from_cache(repo_name)
        return repo

#=======================================================================================
    def get_selected_commit_blob(self):
#=======================================================================================
        '''
        create repository object and save it with cache of repository browser 
        '''
        # if the same repository object has existed in cache then return
        return self.history_broswer.get_selected_commit_blob()

#=======================================================================================
    def udpate_browser(self):
#=======================================================================================
        '''
        description: get the state of file, check if it is tracked or not 
        
        parameter: file_property, dictionary of file property, file-name:(file-status, file-path) 
        parameter: file_path, the absolute path of file, in case that files have the same name
        return   : ('untracked', status) or ('tracked', 'none')
        '''        
        self.repo_broswer.update_files_in_repo()
            
        self.history_broswer.update_history()

#=======================================================================================
    def search_file(self, file_name, keywords, repo):
#=======================================================================================
        '''
        description: interface for searching files which have keywords in their comments 
                     it invokes HistroyBrowser.search_file_keywords( file_name, keywords, repo):
            
        parameter: file_name, the name of target file looked for
        parameter: keywords, keywords in comment
        parameter: repo, the repository object
        return   : blob and commit objects list [(blob, commit)]
        '''
            
        self.history_broswer.search_file_keywords(file_name, keywords, repo)

#=======================================================================================
    def get_auto_save_config(self):
#=======================================================================================
        '''
        description: interface for auto repository config
        '''
        return self.auto_save_repos, self.auto_save_interval

#=======================================================================================
    def update_auto_save_config(self, repo_auto_cofig, new_interval):
#=======================================================================================
        '''
        description: interface for set auto repository config, also uptda config file
            
        parameter: repo_auto_cofig, dictionary, 
                    key: repo_name value: 'yes' for enabling auto-save
                                          'no ' for disabling auto-save
        '''
        self.auto_save_interval = new_interval
        self.auto_save_repos = repo_auto_cofig
        self.config.modify_auto_saved_config(repo_auto_cofig)
        self.config.set_auto_save_interval(new_interval)

#=======================================================================================
    def get_tmp_dir(self):
#=======================================================================================
        '''
        description: get temp directory for comparison
        '''  
        return self.config.get_temp_dir()

#=======================================================================================            
    def get_work_dir(self):
#=======================================================================================
        '''
        description: get DM work directory
        '''  
        return self.config.get_work_dir()


#=======================================================================================            
    def set_compare_tool(self, compare_cmd):
#=======================================================================================
        '''
        description: get DM work directory
        '''  
        return self.config.set_compare_tool(compare_cmd)    

#=======================================================================================            
    def get_compare_tool(self):
#=======================================================================================
        '''
        description: get default copmare tool from config file
        ''' 
        return self.config.get_compare_tool()
    

#=======================================================================================            
    def is_auto_save_active(self):
#=======================================================================================
        '''
        description: ran by thread and commit all auto saved repositories very interval
        ''' 
        # if no repository need to be committed then return
        if len(self.auto_save_repos) == 0:
            return False
        
        # if commit interval is 0 minute then return
        if self.auto_save_interval == 0:
            return False
        
        return True
#=======================================================================================            
    def commit_auto_saved_repo(self):
#=======================================================================================
        '''
        description: ran by thread and commit all auto saved repositories very interval
        '''        
        for repo_name, is_auto_saved in self.auto_save_repos.iteritems():
            if is_auto_saved == "yes":
                # call commit function
                repo_dir = self.repo_dirs[repo_name]
                repo = self.repo_broswer.get_repo_from_cache(repo_name, repo_dir)
                comment = "DM: Auto commit"
                commit_all_files(repo, comment)       
                
                
#=======================================================================================            
    def quit(self):
#=======================================================================================
        '''
        description: release resources and terminate threads if they exit
        '''        
        
        # stop threads
        if self.update_thread.isAlive():
            self.update_thread.stop()
        
        if self.commit_thread.isAlive():
            self.commit_thread.stop()
        
        self.root.destroy()
        
        
#=======================================================================================
class SysMonitorThread(Thread):
#=======================================================================================
    """ 
    A auto commit thread for DM main
    """
#=======================================================================================
    def __init__(self, controller, job, interval=None):
#=======================================================================================
        super(SysMonitorThread, self).__init__()
        self.__controller = controller
        self.stoprequest = Event()
        if job == "update":
            self.__routine = self.__notify_update
            self.__interval = interval * 60
        elif job == "commit":
            self.__routine = self.__notify_commit

#=======================================================================================
    def stop(self):
#=======================================================================================
        '''
        stop thread working
        '''
        self.stoprequest.set()
        
#=======================================================================================
    def run(self):
#=======================================================================================
        '''
        run update or commit routine according thread job
        '''
        while not self.stoprequest.isSet():
            self.__routine()

#=======================================================================================
    def __notify_update(self):
#=======================================================================================       
        '''
        notify DM main to update its repository and file browser
        '''
        sleep(self.__interval)
        self.__controller.udpate_browser()

#=======================================================================================
    def __notify_commit(self):
#=======================================================================================       
        '''
        notify DM main to commit all files in repository
        '''
        if self.__controller.is_auto_save_active():
            # get the commit interval (minutes)
            interval = self.__controller.auto_save_interval
            if interval != 0:
                sleep(interval*60)
                self.__controller.commit_auto_saved_repo()
                self.__controller.udpate_browser()

#=======================================================================================
    def join(self, timeout=None):
#=======================================================================================
        self.stoprequest.set()
        super(SysMonitorThread, self).join(timeout)



#=======================================================================================
def main():
#=======================================================================================
    dm = DMApp()




if __name__ == '__main__':
    main()